package com.google.precinct.client.mapper;

import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.event.MapMoveEndHandler;
import com.google.gwt.maps.client.geocode.Geocoder;
import com.google.gwt.maps.client.geocode.LatLngCallback;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.geom.LatLngBounds;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.InlineHyperlink;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.google.precinct.client.UIUtils;
import com.google.precinct.client.Util;
import com.google.precinct.common.PrecinctInfo;
import com.google.precinct.common.PrecinctService;
import com.google.precinct.common.PrecinctServiceAsync;

public class UnusedMapPrecinctListPanel extends Composite {

	private static PrecinctMapAreaFirstPaneUiBinder uiBinder = GWT
			.create(PrecinctMapAreaFirstPaneUiBinder.class);

	interface PrecinctMapAreaFirstPaneUiBinder extends
			UiBinder<Widget, UnusedMapPrecinctListPanel> {
	}

	private final MapPrecinctRootPanel ctr;

	private final MapWidget maps;
	private int loadPrecinctReqId;


	@UiField
	HTMLPanel loadingPane;

	@UiField
	HTMLPanel unmappedPane;

	@UiField
	HTMLPanel precinctListPane;

	@UiField
	HTMLPanel precinctEmptyPane;

	@UiField
	InlineLabel loadingLabel;

	@UiField
	Label errorLabel;

	@UiField
	InlineHyperlink zoomOut;

	public UnusedMapPrecinctListPanel(MapPrecinctRootPanel ctr,
			MapWidget maps,
			String area) {
		this.ctr = ctr;
		initWidget(uiBinder.createAndBindUi(this));

		this.maps = maps;
		initializeArea(area);
	}

	private void initializeArea(String area) {
		loadingLabel.setText("Retrieving area information...");
		loadingPane.setVisible(true);
		unmappedPane.setVisible(false);

		final String address = area + ", Philippines";
		Geocoder gcoder = new Geocoder();
		gcoder.setBaseCountryCode("ph");
		final int zoomLevel = 11;
		gcoder.getLatLng(address, new LatLngCallback() {

			@Override
			public void onSuccess(LatLng point) {
				Util.track("/PrecinctFinder/02-AreaSelect");
				maps.setCenter(point, zoomLevel);

				loadingLabel.setText("Retrieving Unmapped Precincts... ");

				// Add the maps zoom/move handler so that we detect and cancel request if needed
				loadPrecinctReqId = 1;
				maps.addMapMoveEndHandler(new PrecinctMapMoveEndHandler());

				loadPrecincts(maps.getBounds(), loadPrecinctReqId);
			}

			@Override
			public void onFailure() {
				Util.track("/PrecinctFinder/03-AreaSelectFail");
				fail();
			}

			private void fail() {
				loadingLabel.setText("");
				UIUtils.error(errorLabel, "The area was not found.  Either you entered a too specific area or its incorrectly spelled.  Try cities or towns, like 'cebu'.");
				resetAfterDelay();
			}
		});
	}

	private void loadPrecincts(LatLngBounds bounds, final int requestId) {
		PrecinctServiceAsync service = (PrecinctServiceAsync) GWT.create(PrecinctService.class);

		service.getPrecinctsInBounds(bounds.getSouthWest().getLatitude(),
				bounds.getSouthWest().getLongitude(),
				bounds.getNorthEast().getLatitude(),
				bounds.getNorthEast().getLongitude(),
				new AsyncCallback<List<PrecinctInfo>>() {

					@Override
					public void onSuccess(List<PrecinctInfo> result) {
						if (requestId != loadPrecinctReqId) {
							Util.track("/PrecinctFinder/03-GetPrecinctsCancelled");
							return;
						}
						Util.track("/PrecinctFinder/03-GetPrecincts");

						loadingPane.setVisible(false);

						if (result.size() == 0) {
							precinctEmptyPane.setVisible(true);
						} else {
							precinctListPane.setVisible(true);
							// TODO: Display items here
						}
						unmappedPane.setVisible(true);
					}

					@Override
					public void onFailure(Throwable caught) {
						if (requestId != loadPrecinctReqId) {
							Util.track("/PrecinctFinder/03-GetPrecinctsCancelled");
							return;
						}
						Util.track("/PrecinctFinder/03-GetPrecinctsFail");
						loadingLabel.setText("");
						UIUtils.error(errorLabel, "Failure in getting precinct information.  Please try again later.");
						resetAfterDelay();
					}
				});
	}

	private void resetAfterDelay() {
		(new Timer() {
			@Override
			public void run() {
				ctr.resetFinderInterface();
			}
		}).schedule(5000);
	}

	@UiHandler("zoomOut")
	void onZoomOut(ClickEvent e) {
		maps.zoomOut();
	}

	private class PrecinctMapMoveEndHandler implements MapMoveEndHandler {

		@Override
		public void onMoveEnd(MapMoveEndEvent event) {
			loadPrecinctReqId++;
			loadPrecincts(maps.getBounds(), loadPrecinctReqId);
		}

	}
}
